// UEServiceWorker.cpp
#include <windows.h>
#include <tchar.h>
#include <io.h>
#include <stdio.h>
//GDI+ support
#include <Gdiplus.h>

// UELogger Support
#include "litelog.h"

#include "Base64.h"

// UESever Common Definitions
#include "UEServer.h"
// Class Definition
#include "UEServiceWorker.h"
#include "UEService.h"

CLSID CUEServiceWorker::s_imgClsid = CLSID_NULL;

DWORD WINAPI CUEServiceWorker::WorkingThread(LPVOID lpParam)
{
	CUEServiceWorker *pWorker = (CUEServiceWorker*)lpParam;
	BOOL bResult = TRUE;
	
	dbglogex("Begin handle new connection from %x, port %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, pWorker->m_FromAddr, pWorker->m_FromPort);

	ue_request_header RequestHeader;
	while (bResult)
	{
		bResult = pWorker->ReadRequestHeader(&RequestHeader);
		if (bResult)
		{
			bResult = pWorker->RequestHandler(&RequestHeader);
		} // read request header success
	}

	dbglogex("End handle connection from %x, port %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, pWorker->m_FromAddr, pWorker->m_FromPort);

	delete pWorker;

	return 0;
}

BOOL CUEServiceWorker::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
	UINT  num = 0;          // number of image encoders
	UINT  size = 0;         // size of the image encoder array in bytes

	Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;

	Gdiplus::GetImageEncodersSize(&num, &size);
	if(size == 0)
		return FALSE;  // Failure
	
	pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));
	if(pImageCodecInfo == NULL)
		return FALSE;  // Failure

	Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);

	for(UINT j = 0; j < num; ++j)
	{
		if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
		{
			*pClsid = pImageCodecInfo[j].Clsid;
			free(pImageCodecInfo);
			return TRUE;  // Success
		}
	}

	free(pImageCodecInfo);
	return FALSE;  // Failure
}

CUEServiceWorker::CUEServiceWorker(CUEService *pUEService, int c, int from_addr, int from_port)
{
	m_pUEService = pUEService;
	m_ClientSocket = c;
	m_FromAddr = from_addr;
	m_FromPort = from_port;
	m_nRole = 0;
}

CUEServiceWorker::~CUEServiceWorker()
{
	if (m_ClientSocket > 0)
	{
		closesocket(m_ClientSocket);
		m_ClientSocket = INVALID_SOCKET;
	}
}

BOOL CUEServiceWorker::ReadRequestHeader(ue_request_header* pRequestHeader)
{
	BOOL bResult = TRUE;

	dbglog("Enter CUEServiceWorker::ReadRequestHeader()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	// Read request header
	int len = recv(m_ClientSocket, (char*)pRequestHeader, sizeof(ue_request_header), 0);
	if (len != sizeof(ue_request_header))
	{
		if (len > 0)
		{
			dbglogex("Invalid request, %d bytes read.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, len);
		}
		else
		{
			dbglogex("Read request failed. Error Num: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, WSAGetLastError());
		}
		bResult = FALSE;
	} // read request header failed

	dbglog("Exit CUEServiceWorker::ReadRequestHeader()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
	return bResult;
}

BOOL CUEServiceWorker::RequestHandler(const ue_request_header* pRequestHeader)
{
	BOOL bResult = TRUE;

	dbglog("Enter CUEServiceWorker::RequestHandler()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	switch (pRequestHeader->request_type)
	{
	case UE_REQ_TYPE_STOP:                  // stop service request
		dbglogex("Stop service request from address: %d, port: %d, process %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, pRequestHeader->addr, pRequestHeader->port, pRequestHeader->identifer);
		bResult = HandleStopRequest(pRequestHeader);
		break;
	case UE_REQ_TYPE_AUTH:                  // authentication request
		dbglogex("Authentication request from address: %d, port: %d, process %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, pRequestHeader->addr, pRequestHeader->port, pRequestHeader->identifer);
		bResult = HandleAuthRequest(pRequestHeader);
		break;
	case UE_REQ_TYPE_ACTION:                // action request
		dbglogex("Action request from address: %d, port: %d, process %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, pRequestHeader->addr, pRequestHeader->port, pRequestHeader->identifer);
		bResult = HandleActionRequest(pRequestHeader);
		break;
	case UE_REQ_TYPE_UPDATE:                // update request
		dbglogex("Update request from address: %d, port: %d, process %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, pRequestHeader->addr, pRequestHeader->port, pRequestHeader->identifer);
		bResult = HandleUpdateRequest(pRequestHeader);
		break;
	default:                                // unknown request
		dbglogex("Unknown request type: %d from address: %d, port: %d, process %d", DEBUG_LOG_LEVEL_WARN, logfd, __FILE__, __LINE__, pRequestHeader->request_type, pRequestHeader->addr, pRequestHeader->port, pRequestHeader->identifer);
		bResult = FALSE;
		break;
	} // End of switch

	dbglog("Exit CUEServiceWorker::RequestHandler()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return bResult;
}

BOOL CUEServiceWorker::HandleStopRequest(const ue_request_header *pRequestHeader)
{
	BOOL bResult = TRUE;
	ue_response_header ResponseHeader;

	dbglog("Enter CUEServiceWorker::HandleStopRequest()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	// stop service
	m_pUEService->Stop();

	// prepare response data
	memset(&ResponseHeader, 0, sizeof(ue_response_header));
	ResponseHeader.addr = pRequestHeader->addr;
	ResponseHeader.identifer = pRequestHeader->identifer;
	ResponseHeader.port = pRequestHeader->port;
	ResponseHeader.sequence = pRequestHeader->sequence;
	ResponseHeader.status = UE_RES_STATUS_SUCCESS;
	ResponseHeader.len = 0;

	bResult = SendResponseHeader(&ResponseHeader);

	dbglog("Exit CUEServiceWorker::HandleStopRequest()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return bResult;
}

BOOL CUEServiceWorker::HandleAuthRequest(const ue_request_header *pRequestHeader)
{
	BOOL bResult = TRUE;
	int nStatus = UE_RES_STATUS_SUCCESS;
	int nError;
	ue_response_header ResponseHeader;
	char buf[MAX_PASSWORD_LEN + 1];

	dbglog("Enter CUEServiceWorker::HandleAuthRequest()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	memset(buf, 0, MAX_PASSWORD_LEN + 1);
	// read the authenction key
	if (pRequestHeader->len > 0)
	{
		// validate password length
		if (pRequestHeader->len <= MAX_PASSWORD_LEN && pRequestHeader->len > 1)
		{
			dbglogex("Password length: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, pRequestHeader->len);

			// read password
			nError = readdata(m_ClientSocket, buf, pRequestHeader->len);
			if (!nError)
			{
				dbglogex("Read password success: %s", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, buf);

				// validate password
				if (!strcmp(buf, "admin"))
				{
					dbglog("Password is valid", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
					m_nRole = 1;
				} // password is valid
				else
				{
					dbglogex("Password %s is invalid", DEBUG_LOG_LEVEL_WARN, logfd, __FILE__, __LINE__, buf);
					nStatus = UE_RES_STATUS_FAILED;
				} // password is invalid
			} // read password success
			else
			{
				dbglogex("Read password failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, nError);
				bResult = FALSE;
			} // read password failed
		} // password length is valid
		else
		{
			dbglogex("Password length: %d is invalid", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, pRequestHeader->len);
			nStatus = UE_RES_STATUS_INVALID_REQUEST;
		} // password length is invalid
	} // has authentication key specified
	else
	{
		dbglog("No password specified, we do not allow anonymous access now.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		nStatus = UE_RES_STATUS_FAILED;
	} // no authentication key specified


	// if no error occur, respond client
	if (bResult)
	{
		// prepare response data
		memset(&ResponseHeader, 0, sizeof(ue_response_header));
		ResponseHeader.addr = pRequestHeader->addr;
		ResponseHeader.identifer = pRequestHeader->identifer;
		ResponseHeader.port = pRequestHeader->port;
		ResponseHeader.sequence = pRequestHeader->sequence;
		ResponseHeader.status = nStatus;
		ResponseHeader.len = 0;

		bResult = SendResponseHeader(&ResponseHeader);
	}

	dbglog("Exit CUEServiceWorker::HandleAuthRequest", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return bResult;
}

BOOL CUEServiceWorker::HandleActionRequest(const ue_request_header* pRequestHeader)
{
	BOOL bResult = TRUE;
	int nError;
	char *buf = NULL;
	int nLen = 0;
	int nScreenWidth, nScreenHeight;
	ue_action_data action_data;
	ue_update_data update_data;
	ue_response_header ResponseHeader;
	int nStatus = UE_RES_STATUS_SUCCESS;

	dbglog("Enter CUEServiceWorker::HandleActionRequest()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	// read request action
	if (pRequestHeader->len > 0)
	{
		// validate password length
		if (pRequestHeader->len == sizeof(ue_action_data))
		{
			dbglog("Read action", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

			// read ueid
			nError = readdata(m_ClientSocket, (char*)&action_data, pRequestHeader->len);
			if (!nError)
			{
				dbglog("Read action success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

				// handle action
				switch(action_data.type)
				{
				case UE_ACTION_TYPE_MOUSE_CLICK: // mouse click
					dbglogex("Handle mouse click, %d:%d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, action_data.x, action_data.y);
					SetCursorPos(action_data.x, action_data.y);
					mouse_event(MOUSEEVENTF_LEFTDOWN, 0,0,0,0);
					mouse_event(MOUSEEVENTF_LEFTUP, 0,0,0,0);
					break;                       // end of mouse click
				default:
					//unknown type, do nothing
					dbglogex("Unknown acton type: %d", DEBUG_LOG_LEVEL_WARN, logfd, __FILE__, __LINE__, action_data.type);
					break;
				}

				// TODO: Get image of this UEID
				nLen = GetFullScreen(&buf, &nScreenWidth, &nScreenHeight);
				if (nLen > 0)
				{
					dbglog("Get image of this UEID success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
				} // get image of this ueid success
				else
				{
					dbglog("Get image of this UEID failed", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
					nStatus = UE_RES_STATUS_FAILED;
				} // get image of this ueid failed
			} // read ueid success
			else
			{
				dbglogex("Read action failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, nError);
				bResult = FALSE;
			} // read ueid failed
		} // ueid length is valid
		else
		{
			dbglogex("Action length: %d is invalid", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, pRequestHeader->len);
			nStatus = UE_RES_STATUS_INVALID_REQUEST;
		} // ueid length is invalid
	} // has action specified
	else
	{
		dbglog("No action specified, invalid request.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		nStatus = UE_RES_STATUS_INVALID_REQUEST;
	} // no action specified

	// if no error occur, respond client
	if (bResult)
	{
		// TODO: Get Server UEID
		update_data.ueid = action_data.ueid + 1;
		dbglogex("Get server UEID success: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, update_data.ueid);

		// prepare response data
		update_data.width = nScreenWidth;
		update_data.height = nScreenHeight;
		update_data.count = 1;
		update_data.items = NULL;

		memset(&ResponseHeader, 0, sizeof(ue_response_header));
		ResponseHeader.addr = pRequestHeader->addr;
		ResponseHeader.identifer = pRequestHeader->identifer;
		ResponseHeader.port = pRequestHeader->port;
		ResponseHeader.sequence = pRequestHeader->sequence;
		ResponseHeader.status = nStatus;
		ResponseHeader.len = nLen + sizeof(update_data);

		// send response header
		if (bResult = SendResponseHeader(&ResponseHeader))
		{
			// send response data
			if (ResponseHeader.len > 0)
			{
				nError = senddata(m_ClientSocket, (const char*)&update_data, sizeof(update_data));
				if (!nError)
				{
					dbglog("Send update data success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

					nError = senddata(m_ClientSocket, buf, nLen);
					if (!nError)
					{
						dbglog("Send update data items success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
					}
					else
					{
						dbglogex("Send update data itmes failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, nError);
						bResult = FALSE;
					}
				} // send response data success
				else
				{
					dbglogex("Send update data failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, nError);
					bResult = FALSE;
				} // send response data failed
			} // have data to send
		} // send response header success
	}

	if (buf)
		free(buf);


	dbglog("Exit CUEServiceWorker::HandleActionRequest", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return bResult;
}

BOOL CUEServiceWorker::HandleUpdateRequest(const ue_request_header* pRequestHeader)
{
	BOOL bResult = TRUE;
	int nStatus = UE_RES_STATUS_SUCCESS;
	int nError;
	ue_response_header ResponseHeader;
	int nClientUEID, nServerUEID;
	char *buf = NULL;
	int nLen = 0;
	int nScreenWidth, nScreenHeight;
	ue_update_data update_data;

	dbglog("Enter CUEServiceWorker::HandleUpdateRequest()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	// read request ueid
	if (pRequestHeader->len > 0)
	{
		// validate password length
		if (pRequestHeader->len == sizeof(nClientUEID))
		{
			dbglog("Read UEID", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

			// read ueid
			nError = readdata(m_ClientSocket, (char*)&nClientUEID, pRequestHeader->len);
			if (!nError)
			{
				dbglogex("Read ueid success: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, nClientUEID);

				// TODO: Get image of this UEID
				nLen = GetFullScreen(&buf, &nScreenWidth, &nScreenHeight);
				if (nLen > 0)
				{
					dbglog("Get image of this UEID success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
				} // get image of this ueid success
				else
				{
					dbglog("Get image of this UEID failed", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
					nStatus = UE_RES_STATUS_FAILED;
				} // get image of this ueid failed
			} // read ueid success
			else
			{
				dbglogex("Read ueid failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, nError);
				bResult = FALSE;
			} // read ueid failed
		} // ueid length is valid
		else
		{
			dbglogex("UEID length: %d is invalid", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, pRequestHeader->len);
			nStatus = UE_RES_STATUS_INVALID_REQUEST;
		} // ueid length is invalid
	} // has ueid specified
	else
	{
		dbglog("No ueid specified, invalid request.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		nStatus = UE_RES_STATUS_INVALID_REQUEST;
	} // no ueid specified

	// if no error occur, respond client
	if (bResult)
	{
		// TODO: Get Server UEID
		nServerUEID = nClientUEID + 1;
		dbglogex("Get server UEID success: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, nServerUEID);

		// prepare response data
		update_data.ueid = nServerUEID;
		update_data.width = nScreenWidth;
		update_data.height = nScreenHeight;
		update_data.count = 1;
		update_data.items = NULL;

		memset(&ResponseHeader, 0, sizeof(ue_response_header));
		ResponseHeader.addr = pRequestHeader->addr;
		ResponseHeader.identifer = pRequestHeader->identifer;
		ResponseHeader.port = pRequestHeader->port;
		ResponseHeader.sequence = pRequestHeader->sequence;
		ResponseHeader.status = nStatus;
		ResponseHeader.len = nLen + sizeof(update_data);

		// send response header
		if (bResult = SendResponseHeader(&ResponseHeader))
		{
			// send response data
			if (ResponseHeader.len > 0)
			{
				nError = senddata(m_ClientSocket, (const char*)&update_data, sizeof(update_data));
				if (!nError)
				{
					dbglog("Send update data success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

					nError = senddata(m_ClientSocket, buf, nLen);
					if (!nError)
					{
						dbglog("Send update data items success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
					}
					else
					{
						dbglogex("Send update data itmes failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, nError);
						bResult = FALSE;
					}
				} // send response data success
				else
				{
					dbglogex("Send update data failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, nError);
					bResult = FALSE;
				} // send response data failed
			} // have data to send
		} // send response header success
	}

	if (buf)
		free(buf);

	dbglog("Exit CUEServiceWorker::HandleUpdateRequest", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	return bResult;
}

BOOL CUEServiceWorker::SendResponseHeader(const ue_response_header *pResponseHeader)
{
	BOOL bResult = TRUE;

	dbglog("Enter CUEServiceWorker::SendResponseHeader()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	// Send request header
	int len = send(m_ClientSocket, (char*)pResponseHeader, sizeof(ue_response_header), 0);
	if (len != sizeof(ue_response_header))
	{
		if (len > 0)
		{
			dbglogex("Send response incomplete, %d bytes send.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, len);
		}
		else
		{
			dbglogex("Send response failed. Error Num: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, WSAGetLastError());
		}
		bResult = FALSE;
	} // read request header failed

	dbglog("Exit CUEServiceWorker::SendResponseHeader()", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
	return bResult;
}

int CUEServiceWorker::GetFullScreen(char **pbuf, int *pScreenWidth, int *pScreenHeight)
{
	int nResult = 0;
	int nImageLen = 0;
	char *image = NULL;

	dbglogex("Enter CUEServiceWorker::GetFullScreen(%x)", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, pbuf);

	if (pbuf && pScreenWidth && pScreenHeight)
	{
		*pbuf = NULL;

		HDC hdcScreen = CreateDC(_T("DISPLAY"), NULL, NULL, NULL); 
		HDC hdcCompatible = CreateCompatibleDC(hdcScreen);

		*pScreenWidth = GetDeviceCaps(hdcScreen, HORZRES);
		*pScreenHeight = GetDeviceCaps(hdcScreen, VERTRES);

		// Create a compatible bitmap for hdcScreen. 
		HBITMAP hbmScreen = CreateCompatibleBitmap(hdcScreen, *pScreenWidth, *pScreenHeight);

		// Select the bitmaps into the compatible DC. 
		SelectObject(hdcCompatible, hbmScreen);

		//Copy color data for the entire display into a 
		//bitmap that is selected into a compatible DC.
		BitBlt(hdcCompatible, 
			0,0, 
			*pScreenWidth, *pScreenHeight, 
			hdcScreen, 
			0,0, 
			SRCCOPY);

		Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromHBITMAP(hbmScreen, NULL);

		/* Get temp image file name */
		WCHAR strFilePath[MAX_PATH];
		WCHAR strFileName[MAX_PATH];
		int nLen;
		if (m_pUEService->m_strBaseDir)
		{
			wcscpy_s(strFilePath, MAX_PATH, m_pUEService->m_strBaseDir);
		}
		else
		{
			strFilePath[0] = 0;
		}
		wcscat_s(strFilePath, MAX_PATH, UE_SERVER_TEMP_FOLDER_W);
		dbglogex("Temp image folder: %s", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, strFilePath);
		if (_waccess(strFilePath, 0) == -1)
		{
			dbglog("Create the temp folder since it is not exist", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
			_wmkdir(strFilePath);
		}
		wcscat_s(strFilePath, MAX_PATH, L"uescr");
		nLen = wcslen(strFilePath);
		for (int i = 0; i < INT_MAX; i++)
		{
			_itow_s(i, strFileName, MAX_PATH, 10);
			wcscat_s(strFilePath, MAX_PATH, strFileName);
			wcscat_s(strFilePath, UE_IMAGE_SUFFIX);
			if (_waccess(strFilePath, 0) == -1)
				break;
			strFilePath[nLen] = 0;
		}
		dbglog("Temp image path", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

		Gdiplus::EncoderParameters encoderParameters;
		int quality = UE_IMAGE_QUALITY;
		encoderParameters.Count = 1;
		encoderParameters.Parameter[0].Guid = Gdiplus::EncoderQuality;
		encoderParameters.Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong;
		encoderParameters.Parameter[0].NumberOfValues = 1;
		encoderParameters.Parameter[0].Value = &quality;


		// save image to file
		if (!pBitmap->Save(strFilePath, &s_imgClsid, &encoderParameters))
		{
			dbglog("Save image to file success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

			FILE *file;
			if (!_wfopen_s(&file, strFilePath, L"rb"))
			{
				dbglog("Open the saved image file success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

				fseek(file, 0, SEEK_END);
				nImageLen = ftell(file);
				fseek(file, 0, SEEK_SET);
				if (nImageLen > 0)
				{
					dbglogex("File size: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, nImageLen);
					image = (char*)malloc(nImageLen);
					if (image)
					{
						dbglogex("Malloc memory to load image success.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, *pbuf);

						if (fread(image, 1, nImageLen, file) == nImageLen)
						{
							dbglog("Read image data success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
							
							// encode the data to dataURI format
							nResult = GetEncodeBase64DesLen(nImageLen, 0);
							nResult++;
							nResult += strlen(UE_IMAGE_DATAURI_PREFIX);
							nResult += sizeof(ue_update_item);

							*pbuf = (char*)malloc(nResult);
							if (*pbuf)
							{
								dbglogex("Malloc memory to store file success.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, *pbuf);

								memset(*pbuf, 0, nResult);

								ue_update_item *update_item = (ue_update_item*)*pbuf;
								update_item->left = 0;
								update_item->top = 0;
								update_item->width = *pScreenWidth;
								update_item->height = *pScreenHeight;
								update_item->len = nResult;

								strcpy_s(update_item->data, nResult - sizeof(ue_update_item) - 1, UE_IMAGE_DATAURI_PREFIX);
								EncodeBase64((const unsigned char*)image, (char*)(update_item->data + strlen(UE_IMAGE_DATAURI_PREFIX)), nImageLen, 0);

							} // malloc memory for response data success
							else
							{
								dbglogex("Malloc memory to store file failed.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, *pbuf);
								nResult = 0;
							} // malloc memory for response data failed
						} // read image data success
						else
						{
							dbglog("Read image data failed", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
							nResult = 0;
						} // read image data failed

						free(image);
					} // malloc memory for load image success
					else
					{
						dbglogex("Malloc memory to load iamge failed.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, *pbuf);
						nResult = 0;
					} // malloc memory for load image failed
				} // has image data to read
				fclose(file);
			} // open file success
			else
			{
				dbglog("Open the saved image file failed", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
			} // open fale failed

			// remove the saved file after use it
			_wremove(strFilePath);
		} // save image to file success
		else
		{
			dbglog("Save image to file failed", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		} // save image to file failed

		// clean up
		delete pBitmap;
		DeleteObject(hbmScreen);
		DeleteDC(hdcCompatible);
		DeleteDC(hdcScreen);
	} // parameter check success
	else
	{
		dbglog("Invalid parameter, the pbuf or pScreenWidth or pScreenHeight is null.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
	} // parameter check failed

	dbglogex("Exit CUEServiceWorker::GetFullScreen() with return value: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, nResult);
	return nResult;
}